package com.icehand.utils.xml;

import com.icehand.utils.constants.XmlConst;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * XmlParser
 */
public class XMLParser {

	/**
	 * xml转化成Map
	 * 
	 * @param xmlString string
	 * @return map
	 * @throws ParserConfigurationException ex
	 * @throws IOException ex
	 * @throws SAXException ex
	 */
	public static Map<String, Object> getMapFromXML(String xmlString)
			throws ParserConfigurationException, IOException, SAXException {

		// 这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		InputStream is = InputStreamUtils.getStringStream(xmlString);
		Document document = builder.parse(is);
		// 获取到document里面的全部结点
		NodeList allNodes = document.getFirstChild().getChildNodes();
		Node node;
		Map<String, Object> map = new HashMap<String, Object>();
		int i = 0;
		while (i < allNodes.getLength()) {
			node = allNodes.item(i);
			if (node instanceof Element) {
				map.put(node.getNodeName(), node.getTextContent());
			}
			i++;
		}
		System.out.println(map);
		return map;

	}

	/**
	 * 将对象转化成xml字符串
	 * @param obj object
	 * @return String
	 */
	public static String object2XML(Object obj) {
		xstream.alias(XmlConst.XML, obj.getClass());
		return changeXml(xstream.toXML(obj));
	}

	/**
	 * xml的双下划线改为单下划线
	 * @param strXml string
	 * @return string
	 */
	private static String changeXml(String strXml) {
		try {
			strXml = DocumentHelper.parseText(strXml.replaceAll("__", "_")).asXML();
		} catch (DocumentException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}
		return strXml;
	}

	/**
	 * 扩展xstream，使其支持CDATA块 括号)写错位置了，应该将return new XStream(new XppDriver(new
	 * XmlFriendlyReplacer("-_", "_"))) {当中一个)移到后面的函数的结束;}之中。
	 *
	 */
	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				// 对所有xml节点的转换都增加CDATA标记
				boolean cdata = true;

				@SuppressWarnings("rawtypes")
				public void startNode(String name, Class clazz) {
					super.startNode(name, clazz);
				}

				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write(XmlConst.CDATA_PREFIX);
						writer.write(text);
						writer.write(XmlConst.CDATA_SUFFIX);
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

	public static void main(String[] args) throws Exception {
		String xmlStr = "<xml><return_code>FAIL</return_code>"
				+ "<return_msg>invalid spbill_create_ip</return_msg></xml>";
		Map<String, Object> map = getMapFromXML(xmlStr);

		System.out.println(map);
	}
}
